package com.itheima.wemedia.service.impl;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.common.vo.PageResultVo;
import com.itheima.wemedia.dto.WmNewsContentNodeDto;
import com.itheima.wemedia.dto.WmMaterialPageRequestDto;
import com.itheima.wemedia.dto.WmNewsEnableDto;
import com.itheima.wemedia.mapper.WmNewsMaterialMapper;
import com.itheima.wemedia.mapper.WmUserMapper;
import com.itheima.wemedia.pojo.WmMaterial;
import com.itheima.wemedia.mapper.WmMaterialMapper;
import com.itheima.wemedia.pojo.WmNews;
import com.itheima.common.constants.BusinessConstants;
import com.itheima.common.util.RequestContextUtil;
import com.itheima.common.vo.ResultVo;
import com.itheima.wemedia.dto.WmNewsDtoSave;
import com.itheima.wemedia.mapper.WmNewsMapper;
import com.itheima.wemedia.pojo.WmNewsMaterial;
import com.itheima.wemedia.pojo.WmUser;
import com.itheima.wemedia.service.WmNewsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.wemedia.vo.WmNewsVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @description <p>自媒体图文内容信息 业务实现</p>
 *
 * @version 1.0
 * @package com.itheima.wemedia.service.impl
 */
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {
    //注入素材的mapper层对象
    @Autowired
    private WmMaterialMapper wmMaterialMapper;
    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;
    //注入kafka对象
    @Autowired
    private KafkaTemplate kafkaTemplate;
    //注入用户对象获取文章作者Mapper对象
    @Autowired
    private WmUserMapper wmUserMapper;
    @Value("${url}")
    private String url;

    @Override
    @Transactional
    public Long addWmNews(WmNewsDtoSave wmNewsDtoSave, boolean draft) {

        //创建一个文章对象
        WmNews wmNews = new WmNews();
        //创建文章和素材的关系对象
        WmNewsMaterial wmNewsMaterial = new WmNewsMaterial();
        //从请求头中获取用户id，存入文章对象中
        wmNews.setUserId(RequestContextUtil.getUserId());

        //将请求中的文章内容存入数据库
        String content = wmNewsDtoSave.getContent();
        wmNews.setContent(content);
        //获取请求参数中的频道id存入文章表中
        wmNews.setChannelId(wmNewsDtoSave.getChannelId());
        //添加草稿创建时间
        wmNews.setCreatedTime(LocalDateTime.now());
        //更具请求参数中的draft的值判断时草稿还是提交发布
        if (draft){
            //为true表示时草稿将状态设置为0
            wmNews.setStatus(BusinessConstants.WmNewsConstants.STATUS_DRAFT);
        }else {
            //false表示是提交操作，将状态改为1
            wmNews.setStatus(BusinessConstants.WmNewsConstants.STATUS_SUBMIT);
            wmNews.setEnable(BusinessConstants.WmNewsConstants.ENABLE_ON);
            if (wmNewsDtoSave.getPublishTime()==null){
                wmNews.setPublishTime(LocalDateTime.now());
            }
            wmNews.setSubmitedTime(LocalDateTime.now());
        }
        //判断用户上传的封面是否为空，为空则设置为无图布局
        if (wmNewsDtoSave.getImages().size()<=0){
            wmNews.setType(BusinessConstants.WmNewsConstants.TYPE_NONE_IMG);
        }

        //文章布局不为-1时则表示，不是自动布局，我们需要判断是否有上传封面图片是否等于设置的封面布局属性参数
        //是则将页面传过来的数据存入文章布局中即可
        if (wmNewsDtoSave.getImages().size()==wmNewsDtoSave.getType()){
            wmNews.setType(wmNewsDtoSave.getImages().size());
        }
        //不相等则将用户传入图片的个数设置进文章布局中
        wmNews.setType(wmNewsDtoSave.getImages().size());
        //将获取到的图片数组转换为字符串
        String join = String.join(",", wmNewsDtoSave.getImages());
        wmNews.setImages(join);
        //判断前端提交过来的文章数据是否等于-1，等于-1表示时自动提交则需要，判断文章
        //、内容图片为几张，小于等于0表示为无图文章，小于2是单图文章封面大于等于3是
        //多图封面
        if (BusinessConstants.WmNewsConstants.TYPE_AUTO==wmNewsDtoSave.getType()){
            //设置文章布局，并添加数据到素材文章中间表
            addAuto(wmNews, content,wmNewsMaterial);
        }
        //设置文章标题
        wmNews.setTitle(wmNewsDtoSave.getTitle());
        //将前端传过来的定时发布时间添加到文章对象中
        wmNews.setPublishTime(wmNewsDtoSave.getPublishTime());
        wmNews.setEnable(0);
        wmNews.setLabels(wmNewsDtoSave.getLabels());

        //判断接收前端传过来的参数是否又id有id为修改，将原有的素材文章关系表中的数据删除即可
        if (wmNewsDtoSave.getId()!=null){
            LambdaQueryWrapper<WmNewsMaterial> lqw = new LambdaQueryWrapper<>();
            lqw.eq(WmNewsMaterial::getNewsId,wmNewsDtoSave.getId());
            wmNewsMaterialMapper.delete(lqw);
            //设置文章id，避免执行新增操作
            wmNews.setId(wmNewsDtoSave.getId());
            //更新需要再次审核文章，要将文章修改为待审核
            wmNews.setStatus(BusinessConstants.WmNewsConstants.STATUS_SUBMIT);
            updateById(wmNews);
        }else {
            //执行添加操作
            save(wmNews);
        }

        //添加数据表成功，获取文章内容和封面的内容id,创建一个自媒体素材和文章绑定对象
        addWmNewsMaterial(wmNewsMaterial,wmNews,wmNewsDtoSave.getImages());
        //获取当前文章状态是否为提交并审核
        if (BusinessConstants.WmNewsConstants.STATUS_SUBMIT==wmNews.getStatus()){
            //是提交并审核状态将，文章id发送给kafka
            kafkaTemplate.send(BusinessConstants.MqConstants.HOT_ARTICLE_SCORE_TOPIC,wmNews.getId().toString());
        }
        return wmNews.getId();
    }
    /**
     * 文章的分页查询
     * @param wmMaterialPageRequestDto 接收分页查询数据对象
     * @return 返回分页查询的结果
     */
    @Override
    public PageResultVo findPage(WmMaterialPageRequestDto wmMaterialPageRequestDto) {
        //创建分页查询对象
        IPage<WmNews> iPage = new Page<>(wmMaterialPageRequestDto.getPage(),wmMaterialPageRequestDto.getSize());
        //创建条件查询对象
        LambdaQueryWrapper<WmNews> lqw = new LambdaQueryWrapper<>();
        Long userId = RequestContextUtil.getUserId();
        lqw.eq(WmNews::getUserId,userId);
        lqw.like(StringUtils.isNotEmpty(wmMaterialPageRequestDto.getKeyWord()),WmNews::getTitle,wmMaterialPageRequestDto.getKeyWord());
        lqw.eq(wmMaterialPageRequestDto.getChannelId()!=null,WmNews::getChannelId,wmMaterialPageRequestDto.getChannelId());
        lqw.eq(wmMaterialPageRequestDto.getStatus()!=null,WmNews::getStatus,wmMaterialPageRequestDto.getStatus());
        lqw.ge(wmMaterialPageRequestDto.getBeginPubDate()!=null,WmNews::getSubmitedTime,wmMaterialPageRequestDto.getBeginPubDate());
        lqw.le(wmMaterialPageRequestDto.getEndPubDate()!=null,WmNews::getSubmitedTime,wmMaterialPageRequestDto.getEndPubDate());
        page(iPage,lqw);
        //遍历获取的结果集在url上添加请求ip和端口
        /*List<WmNews> collect = iPage.getRecords().stream().map(m -> {
            for (String s : m.getImages().split(",")) {
                s += url;
                m.setImages(s);
            }
            return m;
        }).collect(Collectors.toList());*/

        return PageResultVo.pageResult(wmMaterialPageRequestDto.getPage(),wmMaterialPageRequestDto.getSize(),iPage.getTotal(),iPage.getRecords());
    }

    /**
     * 根据id查询文章内容
     * @param wmNewsId 文章id
     * @return 返回文章对象
     */
    @Override
    public WmNews findById(Long wmNewsId) {
        //调用方法根据id进行查询
        return getById(wmNewsId);
    }

    /**
     * 根据id删除文章
     * @param id 文章id
     */
    @Override
    public void delete(Long id) {
        removeById(id);
        //更具文章di删除关系表里的文章关系
        LambdaQueryWrapper<WmNewsMaterial> lqw = new LambdaQueryWrapper<>();
        lqw.eq(WmNewsMaterial::getNewsId,id);
        wmNewsMaterialMapper.delete(lqw);
    }

    /**
     * 文章上下架业务功能
     * @param wmNewsEnableDto 接收前端传来的参数
     * @return 返回相应的更新结果
     */
    @Override
    public ResultVo updateEnable(WmNewsEnableDto wmNewsEnableDto) {
        //获取用户传过来的参数
        Integer enable = wmNewsEnableDto.getEnable();
        Long id = wmNewsEnableDto.getId();
        //根据id查询数据库，获取文章对象
        WmNews wmNews = getById(id);
        boolean b= false;
        //判断用户是上架还是下架操作，返回=相应的提示
        if (enable==0){
            //下架
            wmNews.setEnable(BusinessConstants.WmNewsConstants.ENABLE_OFF);
            b = updateById(wmNews);
        }else {
            //上架
            wmNews.setEnable(BusinessConstants.WmNewsConstants.ENABLE_ON);
             b = updateById(wmNews);
        }
        //判断是否上下架成功
        if (b){
            //上下架成功则发送文章id和enable状态到kafka
            Map<String, Long> enableMap = new HashMap<>();
            enableMap.put("article",wmNews.getArticleId());
            enableMap.put("enable",wmNews.getEnable().longValue());
            //kafka只能接收字符串，需要将map集合转换为JSON字符串
            String jsonString = JSON.toJSONString(enableMap);
            //发送消息到kafka
            kafkaTemplate.send(BusinessConstants.MqConstants.WM_NEWS_DOWN_OR_UP_TOPIC,jsonString);
        }
        return ResultVo.ok("文章上下架成功！");
    }

    /**
     * 自媒体审核分页查询
     * @param wmNewsDtoSave 前端传过来的数据
     * @return 返回分页查询到的数据
     */
    @Override
    public PageResultVo findPageList(WmNewsDtoSave wmNewsDtoSave) {
        //创建分页参数
        IPage<WmNews> iPage = new Page<>(wmNewsDtoSave.getPage(),wmNewsDtoSave.getSize());
        //构建查询条件对象
        LambdaQueryWrapper<WmNews> lqw = new LambdaQueryWrapper<>();
        //构建查询条件
        lqw.eq(wmNewsDtoSave.getStatus()!=null,WmNews::getStatus,wmNewsDtoSave.getStatus());
        lqw.like(StringUtils.isNotEmpty(wmNewsDtoSave.getTitle()),WmNews::getTitle,wmNewsDtoSave.getTitle());
        //分页查询数据
        page(iPage,lqw);
        List<WmNews> records = iPage.getRecords();
        //获取用户id
        List<Long> userIds = records.stream().map(WmNews::getUserId).collect(Collectors.toList());
        //根据userIds集合对用户表进行批量查询
        List<WmUser> wmUserList = wmUserMapper.selectBatchIds(userIds);
        //遍历获取到的wmUser对象获取用户名
        //wmUserList.stream().map(m->{wmNewsVo.setAuthorName(m.getName());});
        Map<Long, WmUser> userNameMap = wmUserList.stream().collect(Collectors.toMap(WmUser::getId, Function.identity()));
        //获取分页查询到的结果集进行处理
        List<WmNewsVo> collect = records.stream().map(n -> {

            return WmNewsVo.build(n, userNameMap.get(n.getUserId()));
        }).collect(Collectors.toList());

        //根据id获取
        return PageResultVo.pageResult(wmNewsDtoSave.getPage(),wmNewsDtoSave.getSize(),iPage.getTotal(),collect);
    }

    /**
     * 人工审核通过业务
     * @param wmNewsDtoSave 接收前端传过来的参数
     * @return 返回是否驳回成功
     */
    @Override
    public boolean updateStatus(WmNewsDtoSave wmNewsDtoSave) {
        //根据文章id查询文章对象
        WmNews wmNews = getById(wmNewsDtoSave.getId());
        //判断是否为空
        if (wmNews==null){
            return true;
        }
        //判断状态是否为人工审核
        if (BusinessConstants.WmNewsConstants.STATUS_MANUAL==wmNews.getStatus()){
            //审核则将状态跟新为审核通过
            WmNews updateWmNews = new WmNews();
            updateWmNews.setId(wmNewsDtoSave.getId());
            updateWmNews.setStatus(BusinessConstants.WmNewsConstants.STATUS_MANUAL_PASS);
            return updateById(updateWmNews);
        }
        return false;
    }

    /**
     * 人工审核驳回业务
     * @param wmNewsDtoSave 接收前端传过来的参数
     * @return
     */
    @Override
    public boolean updateStatusFail(WmNewsDtoSave wmNewsDtoSave) {
        //根据文章id查询文章对象
        WmNews wmNews = getById(wmNewsDtoSave.getId());
        //判断是否为空
        if (wmNews==null){
            return true;
        }
        //判断状态是否为人工审核
        if (BusinessConstants.WmNewsConstants.STATUS_MANUAL==wmNews.getStatus()){
            //审核则将状态跟新为审核通过
            WmNews updateWmNews = new WmNews();
            updateWmNews.setId(wmNewsDtoSave.getId());
            updateWmNews.setStatus(BusinessConstants.WmNewsConstants.STATUS_FAIL);
            updateWmNews.setReason(wmNewsDtoSave.getMsg());
            return updateById(updateWmNews);
        }
        return false;
    }

    /**
     * 远程调用查询状态为审核通过和发布时间小于当前时间的文章对象和用户对象
     * 封装为WmNewsVo对象并返回
     * @param wmNewsDtoSave 接收参数，如果定时任务需要进行分片就会用
     * @return 返回查询到的wmNewsVo集合
     */
    @Override
    public List<WmNewsVo> getList(WmNewsDtoSave wmNewsDtoSave) {
        //为了代码的健壮性，如果定时提交的时间为null赋值为当前时间
        if (wmNewsDtoSave.getPublishTime()==null){
            wmNewsDtoSave.setPublishTime(LocalDateTime.now());
        }
        //查询所有状态为8（审核通过的文章），定时发布时间小于等于当前时间的文章
        List<WmNews> list = query()
                .in("status", BusinessConstants.WmNewsConstants.STATUS_PASS,BusinessConstants.WmNewsConstants.STATUS_MANUAL_PASS)
                .le("publish_time", LocalDateTime.now()).list();
        /*List<WmNews> status = query().le("status", BusinessConstants.WmNewsConstants.STATUS_MANUAL_PASS).list();
        if (CollectionUtils.isNotEmpty(status)){
            list.addAll(status);
        }*/
        //判断数据是否为空为空直接return
        if (CollectionUtils.isEmpty(list)){
            return null;
        }
        //遍历集合，获取用户id集合
        List<Long> collect = list.stream().map(WmNews::getUserId).collect(Collectors.toList());
        //根据批量查询用户对象
        Map<Long, WmUser> wmUserMap = wmUserMapper.selectBatchIds(collect).stream().collect(Collectors.toMap(WmUser::getId, Function.identity()));
        //遍历文章集合，封装数据为WmNewsVo对象
        List<WmNewsVo> wmNewsVoList = list.stream().map(n -> {
            //将文章对象和用户对象封装到WmNewsVo数据中
            return WmNewsVo.build(n, wmUserMap.get(n.getUserId()));
        }).collect(Collectors.toList());

        return wmNewsVoList;
    }

    /**
     * 更新文章的状态和文章库的id
     * @param wmNews 接收传过来的文章对象
     * @return 返回是否更新成功
     */
    @Override
    public boolean updateWmNews(WmNews wmNews) {
        return updateById(wmNews);
    }

    /**
     * 有设置文章布局的添加关系表业务
     * @param wmNewsMaterial 关系表对象
     * @param wmNews 文章对象
     */
    private void addWmNewsMaterial(WmNewsMaterial wmNewsMaterial, WmNews wmNews,List<String> images) {
        /*//获取文章中的第一张图片的url
        for (String s : images) {
            String path = removePrefix(s);
            //调用数据库查询素材表，获取素材对象
            LambdaQueryWrapper<WmMaterial> lqw = new LambdaQueryWrapper<>();
            //添加查询条件
            lqw.eq(WmMaterial::getUrl, path);
            //根据条件进行查询获取素材对象
            WmMaterial wmMaterial = wmMaterialMapper.selectOne(lqw);
            //添加数据到素材文章中间表中
            wmNewsMaterial.setMaterialId(wmMaterial.getId());
            //添加文章id到对象中
            wmNewsMaterial.setNewsId(wmNews.getId());
            wmNewsMaterial.setOrd(1);
            //主图引用
            wmNewsMaterial.setType(1);
        }*/
        //判断用户是否是手动指定主图图片，并且上传主图不为空，然后添加数据到主图关系表
        if (CollectionUtils.isNotEmpty(images)) {
            //主图关系表的添加
            addWmNewsM(wmNews, wmNewsMaterial, images, 1);
        }
        //文章图片关系表的添加
        List<WmNewsContentNodeDto> list = JSON.parseArray(wmNews.getContent(), WmNewsContentNodeDto.class);
        List<String> collect = list.stream().filter(n -> BusinessConstants.WmNewsConstants.CONTENT_IMAGE.equals(n.getType()))
                .map(WmNewsContentNodeDto::getValue).collect(Collectors.toList());
        List<String> collect1 = collect.stream().limit(wmNews.getType()).collect(Collectors.toList());
        //自动布局，主图添加到素材 文章中间表中
        addWmNewsM(wmNews,wmNewsMaterial,collect1,1);
        //添加文章图片到素材文章关系表中，进行绑定
        addWmNewsM(wmNews,wmNewsMaterial,collect,0);
    }

    /*public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("zhangsan");
        list.add("lisi");
        list.add("wangwu");
        String s = JSON.toJSONString(list);
        System.out.println(s);
        List<String> images = JSON.parseArray(s,String.class);
        System.out.println(images);
    }*/
    /**
     * 判断文章布局，添加相应的参数
     * @param wmNews 文章对象
     * @param content 文章内容
     */
    private void addAuto(WmNews wmNews, String content,WmNewsMaterial wmNewsMaterial) {
        //解析文本类容为一个对象集合
        List<WmNewsContentNodeDto> list = JSON.parseArray(content, WmNewsContentNodeDto.class);
        //遍历集合取出图片，放进另一个list集合
        //List<WmNewsContentNodeDto> collect = list.stream().filter(n -> BusinessConstants.WmNewsConstants.CONTENT_IMAGE.equals(n.getType())).collect(Collectors.toList());
        List<String> collect = list.stream().filter(n -> BusinessConstants.WmNewsConstants.CONTENT_IMAGE.equals(n.getType())).map(WmNewsContentNodeDto::getValue).collect(Collectors.toList());
        //根据过滤后的集合长度判断封面需要填入的数据
        //主图素材绑定
        if (collect.size()<=0){
            //当文章内容图片小于等于0表示，是无图封面,填入对应的属性
            wmNews.setType(BusinessConstants.WmNewsConstants.TYPE_NONE_IMG);
        }else if(collect.size() <3 ){
            //文章内容中图片小于3，文章布局就为单图布局
            wmNews.setType(BusinessConstants.WmNewsConstants.TYPE_SINGLE_IMG);
            //获取文章中的第一张图片的url
            List<String> collect1 = collect.stream().limit(1).collect(Collectors.toList());
            wmNews.setImages(collect1.get(0));
            //addWmNewsM(wmNews, wmNewsMaterial, collect1,1);
        }else {
            //文章内容中的图片大于3张，布局就是3图布局
            wmNews.setType(BusinessConstants.WmNewsConstants.TYPE_MULTIPLE_IMG);
            //获取文章中的第一张图片的url
            List<String> collect1 = collect.stream().limit(3).collect(Collectors.toList());

            wmNews.setImages(String.join(",", collect1));
            //addWmNewsM(wmNews, wmNewsMaterial, collect1,1);
            //内图片关系添加
        }
        //文章内容与素材绑定
       /* collect.stream().map(n->{
            String path = removePrefix(n);
            //调用数据库查询素材表，获取素材对象
            LambdaQueryWrapper<WmMaterial> lqw = new LambdaQueryWrapper<>();
            //添加查询条件
            lqw.eq(WmMaterial::getUrl, path);
            //根据条件进行查询获取素材对象
            WmMaterial wmMaterial = wmMaterialMapper.selectOne(lqw);
            //添加数据到素材文章中间表中
            wmNewsMaterial.setMaterialId(wmMaterial.getId());
            //添加文章id到对象中
            wmNewsMaterial.setNewsId(wmNews.getId());
            wmNewsMaterial.setOrd(1);
            //主图引用
            wmNewsMaterial.setType(1);
            return wmMaterial;
        });*//*.forEach(System.out::println);*/
        //addWmNewsM(wmNews, wmNewsMaterial, collect,0);
    }

    /**
     * 素材文章中间表的添加
     * @param wmNews
     * @param wmNewsMaterial
     * @param collect1
     * @param type
     */
    private void addWmNewsM(WmNews wmNews, WmNewsMaterial wmNewsMaterial, List<String> collect1,Integer type) {

        for (String s : collect1) {
            String path = removePrefix(s);
            //调用数据库查询素材表，获取素材对象
            LambdaQueryWrapper<WmMaterial> lqw = new LambdaQueryWrapper<>();
            //添加查询条件
            lqw.eq(WmMaterial::getUrl, path);
            //根据条件进行查询获取素材对象
            WmMaterial wmMaterial = wmMaterialMapper.selectOne(lqw);
            //添加数据到素材文章中间表中
            wmNewsMaterial.setMaterialId(wmMaterial.getId());
            //添加文章id到对象中
            wmNewsMaterial.setNewsId(wmNews.getId());
            wmNewsMaterial.setOrd(1);
            //引用类型
            wmNewsMaterial.setType(type);
            wmNewsMaterialMapper.insert(wmNewsMaterial);
        }
    }

    private String removePrefix(String url){
        return url.replaceAll("http://((\\d){1,3}\\.){3}(\\d){1,3}:?(\\d){0,5}\\/", "");
    }
}
